/*
 * $Id: Composite.java 51 2009-04-12 10:04:19Z meyer@alphatec.de $
 * 
 *
 * Copyright 2009 DeltaDesk
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package deltadesk.gui.deltagui.widget;

import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.LinkedList;
import java.util.List;

import deltadesk.gui.deltagui.geom.Insets;
import deltadesk.gui.deltagui.layout.Layout;

/**
 * Composite.
 * 
 * @author Andreas Meyer
 * @version $Revision: 51 $
 */
public class Composite extends Control {
	
	/** The layout manager of this composite. */
	private Layout layout;
	
	/** The list of child controls. */
	protected final List<Control> childControls = new LinkedList<Control>();
	
	/** The insets of the widget. */
	private final Insets insets = new Insets();

	/** The index of the focused control. */
	private int focusIndex = -1;


	/**
	 * @return the layout
	 */
	public Layout getLayout() {
		return layout;
	}

	/**
	 * @param layout the layout to set
	 */
	public void setLayout(final Layout layout) {
		this.layout = layout;
	}
	
	/**
	 * Add a control as child to this composite.
	 * 
	 * @param childWidget
	 */
	public void add(final Control childControl) {
		
		if (childControls.contains(childControl)) {
			throw new IllegalArgumentException(
					"Child is already part of this control");
		}

		childControl.setParent(this);
		childControls.add(childControl);
		
		invalidate();
		setUnrendered();
	}
	
	public Widget get(final int index) {
		return childControls.get(index);
	}
	
	/**
	 * Remove a child control.
	 * 
	 * @param index
	 */
	public void remove(final int index) {

		final Control child = childControls.remove(index);
		child.setParent(null);
		
		invalidate();
		setUnrendered();
	}
	
	/**
	 * Remove all child controls from this composite.
	 * 
	 */
	public void removeAll() {

		for(final Control c : childControls) {

			c.setParent(null);
		} // end for
		childControls.clear();
		
		invalidate();
		setUnrendered();
	}
	
	/**
	 * Return the number of child controls.
	 * 
	 * @return
	 */
	public int getChildCount() {
		return childControls.size();
	}
	
	/**
	 * @return the insets
	 */
	public Insets getInsets() {
		return insets;
	}

	/**
	 * Set the insets.
	 * 
	 * @param insets the insets to set
	 */
	public void setInsets(final Insets insets) {
		
		if(insets != null) {
		
			this.insets.setLeft(insets.getLeft());
			this.insets.setTop(insets.getTop());
			this.insets.setRight(insets.getRight());
			this.insets.setBottom(insets.getBottom());
			this.insets.setGap(insets.getGap());
		}
	}

	/**
	 * Set the insets.
	 * 
	 * @param left
	 * @param top
	 * @param right
	 * @param bottom
	 * @param gap
	 */
	public void setInsets(final int left,
			              final int top,
			              final int right,
			              final int bottom,
			              final int gap) {

		this.insets.setLeft(left);
		this.insets.setTop(top);
		this.insets.setRight(right);
		this.insets.setBottom(bottom);
		this.insets.setGap(gap);
	}
	
	/**
	 * Set the insets.
	 * 
	 * @param all
	 */
	public void setInsets(final int all) {
		setInsets(all, all, all, all, all);
	}

	/**
	 * @see deltadesk.gui.deltagui.widget.Widget#setUnrendered()
	 * 
	 */
	public void setUnrendered() {
		super.setUnrendered();
		
		for(final Control c : childControls) {
			c.setUnrendered();
		}
	}

	/**
	 * @see deltadesk.gui.deltagui.widget.Control#validate()
	 */
	@Override
	public void validate() {

		if (isValid()) {
			return;
		}

		if (!isValid()) {

			if (layout != null) {

				final boolean layouted = layout.layout(this);
				if (layouted) {

					super.validate();
				}
			}

		} // end if

		for (final Control c : childControls) {

			c.validate();
		} // end for

	}

	/**
	 * @see deltadesk.gui.deltagui.widget.Control#render(java.awt.Graphics2D)
	 */
	@Override
	public void render(final Graphics2D g2) {

		super.render(g2);
		
		final Rectangle clipRect = g2.getClipBounds();
		final int w = getWidth();
		final int h = getHeight();
		for(final Control child : childControls) {
			
			final int cx = child.getX();
			final int cy = child.getY();
			final int cw = cx + child.getWidth();
			final int ch = cy + child.getHeight();

			// calculate clipping
			final int clipX, clipY;
			if (cw > w) {
				clipX = w - cx;
			} else {
				clipX = child.getWidth();
			}
			if (ch > h) {
				clipY = h - cy;
			} else {
				clipY = child.getHeight();
			}
			
			// prepare graphics object and paint child
			g2.translate(cx, cy);
			g2.clipRect(0, 0, clipX, clipY);
			child.render(g2);
			
			// revert translation and clipping
			g2.translate(-cx, -cy);
			g2.setClip(clipRect);
		} // end for

		setRendered();
	}

	/**
	 * @see deltadesk.gui.deltagui.widget.Control#setFocus()
	 */
	@Override
	void setFocus() {
		
		if(childControls.size() > 0 && childControls.get(0).isFocusable()) {
			
			childControls.get(0).setFocus();
			this.focusIndex = 0;
		} else {

			super.setFocus();
		}
	}
	
	/**
	 * Focus the next control in this composite.
	 * 
	 */
	public void focusNext() {
		
		focusIndex++;
		if(focusIndex >= childControls.size()) {
			focusIndex = 0;
		}
		Control.focusedControl.setUnfocused();
		childControls.get(focusIndex).setFocus();
	}
	
	/**
	 * Focus the previous control in this composite.
	 * 
	 */
	public void focusPrevious() {

		focusIndex--;
		if(focusIndex < 0) {
			focusIndex = childControls.size() - 1;
		}
		Control.focusedControl.setUnfocused();
		childControls.get(focusIndex).setFocus();
	}

}
